#ifndef _TBOX_H_
#define _TBOX_H_

#include "rads_base.hpp"

#include <iostream>  
#include <sstream>  
#include <fstream>
#include <fcntl.h>  
#include <termios.h>  
#include <unistd.h>  
#include <cstring>  
#include <vector> 
#include <thread>
#include <cmath>
#include <queue>
#include <chrono> 
#include <ctime>
#include <condition_variable>

// socket tcp for rtcm 
#include <arpa/inet.h>  
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h> 
#include <netdb.h>  

// ros info
#include <ros/ros.h>
#include <ros/time.h>
#include <std_msgs/String.h>
#include <std_msgs/ByteMultiArray.h>

// AES-256-CBC lcrypto
#include <openssl/conf.h>  
#include <openssl/evp.h>  
#include <openssl/err.h>  
#include <string.h>  
// 256位密钥需要32字节
#define AES_KEY "01234567890123456789012345678901"
// 初始化向量需要16字节
#define AES_IV "0123456789012345"

#include <rads/rads_trackext.h>
#include <rads/rads_cmd.h>
#include <rads/rads_scmd.h>
#include <rads/rads_apis.h>
#include <rads/rads_acks.h>
#include <rads/rads_guard.h>
#include <rads/rads_log.h>

// json
#include "json.hpp"
#define BUFFER_SIZE 1024
using json = nlohmann::json;

struct VehicleRunInfo {
    std::string vehicle_id;	// 车辆编号
    int model;				// 运行模式
    int err;				// 错误编号
    double lng;				// 经度
    double lat;				// 纬度
    double alt;				// 高程
    double soc;				// 电池电量
    double soh;				// 电池健康
    int    fix_posi;		// 定位解
    int    fix_head;		// 航向解
    double heading;			// 航向（正北0度）
    double fx;				// 融合之后的x坐标
    double fy;				// 融合之后的y坐标
    double fz;				// 融合之后的z坐标
    double yaw;				// 位姿-航向角
    double pitch;			// 位姿-俯仰角
    double roll;			// 位姿-翻滚角
    double speed;			// 地面速度
    double ndt;				// NDT匹配率
    int rads_ready;         // 自动驾驶是否就绪
    long long ts;			// 当前系统时间戳
    int heartbeat;			// 心跳编码
    friend void to_json(json& j, const VehicleRunInfo& v) {
        j = json{{"vehicle_id", v.vehicle_id}, {"model", v.model}, {"errno", v.err}, {"lng", v.lng}, {"lat", v.lat}, {"alt", v.alt}, {"soc", v.soc}, {"soh", v.soh}, {"fix_posi", v.fix_posi}, {"fix_head", v.fix_head}, {"heading", v.heading}, {"fx", v.fx}, {"fy", v.fy}, {"fz", v.fz}, {"fz", v.fz}, {"yaw", v.yaw}, {"pitch", v.pitch}, {"roll", v.roll}, {"speed", v.speed}, {"ndt", v.ndt},{"rads_ready", v.rads_ready}, {"ts", v.ts}, {"heartbeat", v.heartbeat}};
    }
    friend void from_json(const json& j, VehicleRunInfo& v) {
        j.at("vehicle_id").get_to(v.vehicle_id);
        j.at("model").get_to(v.model);
        j.at("errno").get_to(v.err);
        j.at("lng").get_to(v.lng);
        j.at("lat").get_to(v.lat);
        j.at("alt").get_to(v.alt);
        j.at("soc").get_to(v.soc);
        j.at("soh").get_to(v.soh);
        j.at("fix_posi").get_to(v.fix_posi);
        j.at("fix_head").get_to(v.fix_head);
        j.at("heading").get_to(v.heading);
        j.at("fx").get_to(v.fx);
        j.at("fy").get_to(v.fy);
        j.at("fz").get_to(v.fz);
        j.at("yaw").get_to(v.yaw);
        j.at("pitch").get_to(v.pitch);
        j.at("roll").get_to(v.roll);
        j.at("speed").get_to(v.speed);
        j.at("ndt").get_to(v.ndt);
        j.at("rads_ready").get_to(v.rads_ready);
        j.at("ts").get_to(v.ts);
        j.at("heartbeat").get_to(v.heartbeat);
    }
};


typedef struct
{
  int64_t recv_ts;           // 接收网络指令时系统的时间
  std::string nema;			 //
  std::string head;          // ##
  std::string vehicle_id;    // 设备编号
  int cmd;                   // 命令项
  int cmd_opt;               // 命令选配扩展位2
  int ext;                   // 扩展位1
  int ext2;                  // 扩展位2
  std::vector<int> data;
}NetCmdObsolete;

typedef struct
{
    std::string prev_nema;
    int64_t prev_nema_ts;
    int64_t prev_seq;
}PrevCmdRecord;

typedef struct
{
    std::string head;         // ##
    std::string vehicle_id;   // 设备编号
    int model;                // 模式标识
    int status;               // 状态位号
    int fun;                  // 功能编号
    int ext;                  // 扩展位1
    int ext2;                 // 扩展位2
}NetCmd;

typedef struct{
    int64_t level;		 		// "0-DEBUG","1-INFO","2-WARN","3-ERROR","4-FATAL"
    int64_t ts;					// system rostime
    int64_t code;			    // SensorWarningLog & VehicleStatus
    std::string desc;			// 详细描述
    std::string remark;			// 备注信息
    int64_t ext;
    std::string ext2;
    int status;					// def:-1,待发布 = 0，已发布 = 1
    int64_t ts_send;			// 发布时间
}CacheLog;

void CacheMsg2Log(CacheLog& cache,const rads::rads_log& log)
{
    cache.level = log.level;
    cache.ts = log.ts;
    cache.code = log.code;
    cache.desc = log.desc;
    cache.remark = log.remark;
    cache.ext = log.ext;
    cache.ext2 = log.ext2;
    cache.status = -1;
}

typedef struct{
    std::queue<CacheLog> debug;
	std::queue<CacheLog> info;
    std::queue<CacheLog> warn;
    std::queue<CacheLog> error;
    std::queue<CacheLog> fatal;
}CacheLogs;

// 多个数据监听源
typedef struct
{
    // 内部响应,转发API
    rads::rads_apis _api;
    // 下位机数据
    rads::rads_scmd _scmd;
    // 定位数据
    rads::rads_trackext _gnss;
    // 警告信息
    rads::rads_guard _guard;
    // 日志消息1
    rads::rads_log _log;
    // 日志管理2
    CacheLogs logs;
    // 发布网络指令
    rads::rads_cmd _cmd;
    // 融合之后的数据
     rads::rads_trackext _fusion;
    // 上报的内容tbox
    VehicleRunInfo _vri;
    // 发送的flag
    int tbox_report;
}MultListen;

// 来自网络端的字符串数据解析
NetCmdObsolete DecodeNetCmdObsolete(std::string cloud_message)
{
    NetCmdObsolete cmd_obsolete;
    std::vector<std::string>  vec = splitStr(cloud_message,',');
    if(vec.size() > 4)
    {
        cmd_obsolete.recv_ts = current_timestamp_ms();
        cmd_obsolete.nema = cloud_message;
        cmd_obsolete.head = vec[0].substr(0,2);
        cmd_obsolete.vehicle_id = vec[0].substr(2,vec[0].length()-2);
        cmd_obsolete.cmd = atoi(vec[1].c_str());
        cmd_obsolete.cmd_opt = atoi(vec[2].c_str());
        cmd_obsolete.ext = atoi(vec[3].c_str());
        cmd_obsolete.ext2 = atoi(vec[4].c_str());
        // 针对 图,线,站点,分部调度
		if(CMDO_STATION_NAV == cmd_obsolete.cmd)
        {
            int len =  cmd_obsolete.ext2;
            if(vec.size() > (len + 4))
            {
                for(int i = 0; i < len; i++)
                {
                    cmd_obsolete.data.push_back(atoi(vec[i+5].c_str()));
                }
            }
        }
        // 途经点导航
        else if(CMDO_PASSPOINT_NAV == cmd_obsolete.cmd)
        {
            int  index = 5;
            int len = cmd_obsolete.ext;
            for(int i = 0;i < len*2;i = i+2)
            {
                cmd_obsolete.data.push_back(atoi(vec[index+i].c_str()));
                cmd_obsolete.data.push_back(atoi(vec[index+i+1].c_str()));
            }
        }
    }
    return cmd_obsolete;
}

void Cmd2radsmsg(NetCmdObsolete cmd,rads::rads_cmd& _cmd)
{
    _cmd.header.stamp = ros::Time::now();
    _cmd.header.frame_id = "nyd-net";
    _cmd.pro_nema = cmd.nema;
	_cmd.pro_head = cmd.head;
	_cmd.pro_vehsn = cmd.vehicle_id;
	_cmd.pro_cmd = cmd.cmd;
	_cmd.pro_cmd_opt = cmd.cmd_opt;
	_cmd.pro_ext1 = cmd.ext;
	_cmd.pro_ext2 = cmd.ext2;
    _cmd.data.clear();
	if(cmd.data.size() > 0)
	{
		for (int val : cmd.data) {_cmd.data.push_back(val);}
	}
}


void handleErrors(void) {  
    ERR_print_errors_fp(stderr);  
    abort();  
}  

// 加密
int encrypt(unsigned char *plaintext, int plaintext_len,unsigned char *ciphertext) {  
    EVP_CIPHER_CTX *ctx;  
    int len;  
    int ciphertext_len;
	unsigned char *key = (unsigned char *)AES_KEY;
    unsigned char *iv = (unsigned char *)AES_IV; 
    if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();  
    if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))  
        handleErrors();  
    if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))  
        handleErrors();  
    ciphertext_len = len;  
    if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors();  
    ciphertext_len += len;  
    EVP_CIPHER_CTX_free(ctx);  
    return ciphertext_len;  
}  
 
// 解密
int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *plaintext) {  
    EVP_CIPHER_CTX *ctx;  
    int len;  
    int plaintext_len;  
	unsigned char *key = (unsigned char *)AES_KEY;
    unsigned char *iv = (unsigned char *)AES_IV; 
    if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();  
    if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))  
        handleErrors();  
    if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))  
        handleErrors();  
    plaintext_len = len;  
    if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) handleErrors();  
    plaintext_len += len;  
    EVP_CIPHER_CTX_free(ctx);  
    return plaintext_len;  
}  

void sendFile(int socketFd, const std::string& filename) {  
	std::ifstream file(filename, std::ios::binary);  
	if (!file) {  
		DEBUG_WARN("Failed to open file");
		return;  
	}  
	char buffer[BUFFER_SIZE];  
	while (!file.eof()) {  
		file.read(buffer, BUFFER_SIZE);  
		ssize_t bytesRead = file.gcount();  
		ssize_t bytesSent = send(socketFd, buffer, bytesRead, 0);  
		if (bytesSent != bytesRead) {  
			DEBUG_WARN("Failed to send file");
			break;  
		}  
	}  
	file.close();  
	char fileEndFlag = '\0';  
	send(socketFd, &fileEndFlag, sizeof(char), 0);  
} 

class TCPClient {  
	public:  
		TCPClient(const std::string& server_ip, int server_port)  
			: server_ip_(server_ip), server_port_(server_port), sockfd_(-1) {
                err_ = 0;
			}

		~TCPClient() {  
			if (sockfd_ != -1) {  
				close(sockfd_);  
			}  
		}  
        int GetErr(){return err_;}
        void selfClose()
        {
		    if (sockfd_ != -1) {
		        close(sockfd_);
		    }
        }
		bool connectToServer() {  
			struct sockaddr_in server_addr;  
			memset(&server_addr, 0, sizeof(server_addr));  
			server_addr.sin_family = AF_INET;  
			server_addr.sin_port = htons(server_port_);  
			inet_pton(AF_INET, server_ip_.c_str(), &server_addr.sin_addr);  
			sockfd_ = socket(AF_INET, SOCK_STREAM, 0);  
			if (sockfd_ < 0) {  
				DEBUG_WARN("Failed to create socket");
				return false;  
			}  
			if (connect(sockfd_, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {  
				DEBUG_WARN("Failed to connect to server");
				close(sockfd_);  
				sockfd_ = -1;  
				return false;  
			}  
			// 在连接成功后，使用 fcntl 函数将套接字设置为非阻塞模式
			int flags = fcntl(sockfd_, F_GETFL, 0);  
			if (flags == -1) {  
				DEBUG_WARN("Failed to get socket flags");
				close(sockfd_);  
				sockfd_ = -1;  
				return false;  
			}  
			if (fcntl(sockfd_, F_SETFL, flags | O_NONBLOCK) == -1) {   
				DEBUG_WARN("Failed to set socket to non-blocking mode");
				close(sockfd_);  
				sockfd_ = -1;  
				return false;  
			} 
			return true;  
		}  

		bool authenticate(const std::string& username, const std::string& password) {  
			std::string auth_msg = "##," + username + "," + password + "," + KTV_SN + ",";
            
			if (!sendData(auth_msg)) {  
				return false;  
			}
		    std::this_thread::sleep_for(std::chrono::milliseconds(500));
			char response[1024];  
			int bytes_received = recv(sockfd_, response, sizeof(response) - 1, 0);  
			if (bytes_received < 0) {  
				DEBUG_WARN("Failed to receive authentication response");
				return false;  
			}  
			response[bytes_received] = '\0';
			if (std::string(response).find("AUTH OK") != 0) {  
				DEBUG_WARN("Authentication failed");  
				return false;  
			}
			return true;  
		}  
		bool sendData(const std::string& data) {  
            //std::cout << "data:::" << data.c_str() << std::endl;
			ssize_t bytes_sent = send(sockfd_, data.c_str(), data.size(), 0);  
            //std::cout << "bytes_sent:::" << bytes_sent << std::endl;
			if (bytes_sent < 0 || bytes_sent != data.size()) {  
				DEBUG_WARN("[tbox]Failed to send data");
				return false;  
			}  
			return true;  
		}  
		bool receiveData(std::string& data) {  
			char buffer[1024];  
			int bytes_received = recv(sockfd_, buffer, sizeof(buffer) - 1, 0);  
			if (bytes_received < 0) {  
				DEBUG_WARN("[tbox]Failed to receive data");
				return false;  
			}  
			buffer[bytes_received] = '\0';
			data = std::string(buffer);  
			return true;  
		}  
		bool receiveDataNoblock(std::string& data, int timeout_ms = 100) {  
			char buffer[1024];  
			ssize_t bytes_received;  
			fd_set read_fds;  
			struct timeval timeout;  
			FD_ZERO(&read_fds);  
			FD_SET(sockfd_, &read_fds);  
			timeout.tv_sec = timeout_ms / 1000;  
			timeout.tv_usec = (timeout_ms % 1000) * 1000;  
			int result = select(sockfd_ + 1, &read_fds, nullptr, nullptr, &timeout);  
			if (result == -1) {  
				DEBUG_WARN("select error");
				return false;  
			} else if (result == 0) {  
			//	DEBUG_WARN("Timeout occurred while waiting for data");
				return false; 
			}  
			bytes_received = recv(sockfd_, buffer, sizeof(buffer) - 1, 0);  
			if (bytes_received == 0) {  
				DEBUG_WARN("Connection closed by server");
			    err_ = -1;
				return false;  
			} else if (bytes_received < 0) {  
				if (errno == EAGAIN || errno == EWOULDBLOCK) {  
					DEBUG_WARN("No data available, but no error (non-blocking)");  
					return false;
				} else {  
					DEBUG_WARN("Failed to receive data"); 
					return false;  
				}  
			}  
			buffer[bytes_received] = '\0';  
			data = std::string(buffer);  
			return true;  
		}  

	private:  
		std::string server_ip_;  
		int server_port_;  
		int sockfd_;
        int err_;
};  

#endif
